package com.mysteel.monitor.core.utils;


import com.mysteel.monitor.core.model.ThreadMonitorInfo;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.*;

public class ThreadRenderUitl {

    private static  final  int sampleInterval = 100;

    public static List<ThreadMonitorInfo>  renderer(Iterator<Thread> stream) {

        //
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

        //
        List<Thread> threads = Utils.list(stream);

        // Sample CPU
        Map<Long, Long> times1 = new HashMap<Long, Long>();
        for (Thread thread : threads) {
            long cpu = threadMXBean.getThreadCpuTime(thread.getId());
            times1.put(thread.getId(), cpu);
        }
        try {
            Thread.sleep(sampleInterval);
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // Resample
        Map<Long, Long> times2 = new HashMap<Long, Long>(threads.size());
        for (Thread thread : threads) {
            long cpu = threadMXBean.getThreadCpuTime(thread.getId());
            times2.put(thread.getId(), cpu);
        }

        // Compute delta map and total time
        long total = 0;
        Map<Long, Long> deltas = new HashMap<Long, Long>(threads.size());
        for (Long id : times2.keySet()) {
            long time1 = times2.get(id);
            long time2 = times1.get(id);
            if (time1 == -1) {
                time1 = time2;
            } else if (time2 == -1) {
                time2 = time1;
            }
            long delta = time2 - time1;
            deltas.put(id, delta);
            total += delta;
        }

        // Compute cpu
        final HashMap<Thread, Long> cpus = new HashMap<Thread, Long>(threads.size());
        for (Thread thread : threads) {
            long cpu = total == 0 ? 0 : Math.round((deltas.get(thread.getId()) * 100) / total);
            cpus.put(thread, cpu);
        }

        // Sort by CPU time : should be a rendering hint...
        Collections.sort(threads, (o1, o2) -> {
            long l1 = cpus.get(o1);
            long l2 = cpus.get(o2);
            if (l1 < l2) {
                return 1;
            } else if (l1 > l2) {
                return -1;
            } else {
                return 0;
            }
        });

        List<ThreadMonitorInfo> threadMonitorInfoList = new ArrayList<>();
        ThreadMonitorInfo  monitorInfo = null;
        for (Thread thread : threads) {
            long seconds = times2.get(thread.getId()) / 1000000000;
            long min = seconds / 60;
            String time = min + ":" + (seconds % 60);
            ThreadGroup group = thread.getThreadGroup();
            monitorInfo = ThreadMonitorInfo.builder()
                    .id(thread.getId())
                    .name(thread.getName())
                    .group(group == null ? "" : group.getName())
                    .priority(thread.getPriority())
                    .state(thread.getState().name())
                    .interrupted(thread.isInterrupted())
                    .cpu(cpus.get(thread))
                    .time(time)
                    .daemon(thread.isDaemon())
                    .build();
            threadMonitorInfoList.add(monitorInfo);
        }
        // 监视器
        return threadMonitorInfoList;
    }
}
